'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.nodeContextTypes = undefined;

var _typeof2 = require('babel-runtime/helpers/typeof');

var _typeof3 = _interopRequireDefault(_typeof2);

var _defineProperty2 = require('babel-runtime/helpers/defineProperty');

var _defineProperty3 = _interopRequireDefault(_defineProperty2);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');

var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);

var _inherits2 = require('babel-runtime/helpers/inherits');

var _inherits3 = _interopRequireDefault(_inherits2);

var _extends2 = require('babel-runtime/helpers/extends');

var _extends3 = _interopRequireDefault(_extends2);

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _classnames = require('classnames');

var _classnames2 = _interopRequireDefault(_classnames);

var _warning = require('warning');

var _warning2 = _interopRequireDefault(_warning);

var _animate = require('../animate');

var _animate2 = _interopRequireDefault(_animate);

var _toArray = require('../util/Children/toArray');

var _toArray2 = _interopRequireDefault(_toArray);

var _Tree = require('./Tree');

var _util = require('./util');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var ICON_OPEN = 'open';
var ICON_CLOSE = 'close';

var defaultTitle = '---';

var onlyTreeNodeWarned = false; // Only accept TreeNode

var nodeContextTypes = exports.nodeContextTypes = (0, _extends3['default'])({}, _Tree.contextTypes, {
  rcTreeNode: _propTypes2['default'].shape({
    onUpCheckConduct: _propTypes2['default'].func
  })
});

var TreeNode = function (_React$Component) {
  (0, _inherits3['default'])(TreeNode, _React$Component);

  function TreeNode(props) {
    (0, _classCallCheck3['default'])(this, TreeNode);

    var _this = (0, _possibleConstructorReturn3['default'])(this, _React$Component.call(this, props));

    _initialiseProps.call(_this);

    _this.state = {
      dragNodeHighlight: false
    };
    return _this;
  }

  TreeNode.prototype.getChildContext = function getChildContext() {
    return (0, _extends3['default'])({}, this.context, {
      rcTreeNode: {
        onUpCheckConduct: this.onUpCheckConduct
      }
    });
  };

  // Isomorphic needn't load data in server side


  TreeNode.prototype.componentDidMount = function componentDidMount() {
    this.syncLoadData(this.props);
  };

  TreeNode.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
    this.syncLoadData(nextProps);
  };

  // Disabled item still can be switch


  // Drag usage


  TreeNode.prototype.isSelectable = function isSelectable() {
    var selectable = this.props.selectable;
    var treeSelectable = this.context.rcTree.selectable;

    // Ignore when selectable is undefined or null

    if (typeof selectable === 'boolean') {
      return selectable;
    }

    return treeSelectable;
  };

  // Load data to avoid default expanded tree without data


  // Switcher


  // Checkbox


  // Icon + Title


  // Children list wrapped with `Animation`


  TreeNode.prototype.render = function render() {
    var _classNames;

    var loading = this.props.loading;
    var _props = this.props,
        className = _props.className,
        dragOver = _props.dragOver,
        dragOverGapTop = _props.dragOverGapTop,
        dragOverGapBottom = _props.dragOverGapBottom,
        isLeaf = _props.isLeaf,
        expanded = _props.expanded,
        selected = _props.selected,
        checked = _props.checked,
        halfChecked = _props.halfChecked;
    var _context$rcTree = this.context.rcTree,
        prefixCls = _context$rcTree.prefixCls,
        filterTreeNode = _context$rcTree.filterTreeNode;

    var disabled = this.isDisabled();

    return _react2['default'].createElement('li', {
      className: (0, _classnames2['default'])(className, (_classNames = {}, (0, _defineProperty3['default'])(_classNames, prefixCls + '-treenode-disabled', disabled), (0, _defineProperty3['default'])(_classNames, prefixCls + '-treenode-switcher-' + (expanded ? 'open' : 'close'), !isLeaf), (0, _defineProperty3['default'])(_classNames, prefixCls + '-treenode-checkbox-checked', checked), (0, _defineProperty3['default'])(_classNames, prefixCls + '-treenode-checkbox-indeterminate', halfChecked), (0, _defineProperty3['default'])(_classNames, prefixCls + '-treenode-selected', selected), (0, _defineProperty3['default'])(_classNames, prefixCls + '-treenode-loading', loading), (0, _defineProperty3['default'])(_classNames, 'drag-over', !disabled && dragOver), (0, _defineProperty3['default'])(_classNames, 'drag-over-gap-top', !disabled && dragOverGapTop), (0, _defineProperty3['default'])(_classNames, 'drag-over-gap-bottom', !disabled && dragOverGapBottom), (0, _defineProperty3['default'])(_classNames, 'filter-node', filterTreeNode && filterTreeNode(this)), _classNames)),

      onDragEnter: this.onDragEnter,
      onDragOver: this.onDragOver,
      onDragLeave: this.onDragLeave,
      onDrop: this.onDrop,
      onDragEnd: this.onDragEnd
    }, this.renderSwitcher(), this.renderCheckbox(), this.renderSelector(), this.renderChildren());
  };

  return TreeNode;
}(_react2['default'].Component);

TreeNode.propTypes = {
  eventKey: _propTypes2['default'].string, // Pass by parent `cloneElement`
  prefixCls: _propTypes2['default'].string,
  className: _propTypes2['default'].string,
  root: _propTypes2['default'].object,
  onSelect: _propTypes2['default'].func,

  // By parent
  expanded: _propTypes2['default'].bool,
  selected: _propTypes2['default'].bool,
  checked: _propTypes2['default'].bool,
  loaded: _propTypes2['default'].bool,
  loading: _propTypes2['default'].bool,
  halfChecked: _propTypes2['default'].bool,
  children: _propTypes2['default'].node,
  title: _propTypes2['default'].node,
  pos: _propTypes2['default'].string,
  dragOver: _propTypes2['default'].bool,
  dragOverGapTop: _propTypes2['default'].bool,
  dragOverGapBottom: _propTypes2['default'].bool,

  // By user
  isLeaf: _propTypes2['default'].bool,
  selectable: _propTypes2['default'].bool,
  disabled: _propTypes2['default'].bool,
  disableCheckbox: _propTypes2['default'].bool,
  icon: _propTypes2['default'].oneOfType([_propTypes2['default'].node, _propTypes2['default'].func])
};
TreeNode.contextTypes = nodeContextTypes;
TreeNode.childContextTypes = nodeContextTypes;
TreeNode.defaultProps = {
  title: defaultTitle
};

var _initialiseProps = function _initialiseProps() {
  var _this2 = this;

  this.onUpCheckConduct = function (treeNode, nodeChecked, nodeHalfChecked, e) {
    var nodePos = treeNode.props.pos;
    var _props2 = _this2.props,
        eventKey = _props2.eventKey,
        pos = _props2.pos,
        checked = _props2.checked,
        halfChecked = _props2.halfChecked;
    var _context = _this2.context,
        _context$rcTree2 = _context.rcTree,
        checkStrictly = _context$rcTree2.checkStrictly,
        isKeyChecked = _context$rcTree2.isKeyChecked,
        onBatchNodeCheck = _context$rcTree2.onBatchNodeCheck,
        onCheckConductFinished = _context$rcTree2.onCheckConductFinished,
        _context$rcTreeNode = _context.rcTreeNode;
    _context$rcTreeNode = _context$rcTreeNode === undefined ? {} : _context$rcTreeNode;
    var onUpCheckConduct = _context$rcTreeNode.onUpCheckConduct;

    // Stop conduct when current node is disabled

    if ((0, _util.isCheckDisabled)(_this2)) {
      onCheckConductFinished(e);
      return;
    }

    var children = _this2.getNodeChildren();

    var checkedCount = nodeChecked ? 1 : 0;

    // Statistic checked count
    children.forEach(function (node, index) {
      var childPos = (0, _util.getPosition)(pos, index);

      if (nodePos === childPos || (0, _util.isCheckDisabled)(node)) {
        return;
      }

      if (isKeyChecked(node.key || childPos)) {
        checkedCount += 1;
      }
    });

    // Static enabled children count
    var enabledChildrenCount = children.filter(function (node) {
      return !(0, _util.isCheckDisabled)(node);
    }).length;

    // checkStrictly will not conduct check status
    var nextChecked = checkStrictly ? checked : enabledChildrenCount === checkedCount;
    var nextHalfChecked = checkStrictly ? // propagated or child checked
    halfChecked : nodeHalfChecked || checkedCount > 0 && !nextChecked;

    // Add into batch update
    if (checked !== nextChecked || halfChecked !== nextHalfChecked) {
      onBatchNodeCheck(eventKey, nextChecked, nextHalfChecked);

      if (onUpCheckConduct) {
        onUpCheckConduct(_this2, nextChecked, nextHalfChecked, e);
      } else {
        // Flush all the update
        onCheckConductFinished(e);
      }
    } else {
      // Flush all the update
      onCheckConductFinished(e);
    }
  };

  this.onDownCheckConduct = function (nodeChecked) {
    var children = _this2.props.children;
    var _context$rcTree3 = _this2.context.rcTree,
        checkStrictly = _context$rcTree3.checkStrictly,
        isKeyChecked = _context$rcTree3.isKeyChecked,
        onBatchNodeCheck = _context$rcTree3.onBatchNodeCheck;

    if (checkStrictly) return;

    (0, _util.traverseTreeNodes)(children, function (_ref) {
      var node = _ref.node,
          key = _ref.key;

      if ((0, _util.isCheckDisabled)(node)) return false;

      if (nodeChecked !== isKeyChecked(key)) {
        onBatchNodeCheck(key, nodeChecked, false);
      }
    });
  };

  this.onSelectorClick = function (e) {
    // Click trigger before select/check operation
    var onNodeClick = _this2.context.rcTree.onNodeClick;

    onNodeClick(e, _this2);

    if (_this2.isSelectable()) {
      _this2.onSelect(e);
    } else {
      _this2.onCheck(e);
    }
  };

  this.onSelectorDoubleClick = function (e) {
    var onNodeDoubleClick = _this2.context.rcTree.onNodeDoubleClick;

    onNodeDoubleClick(e, _this2);
  };

  this.onSelect = function (e) {
    if (_this2.isDisabled()) return;

    var onNodeSelect = _this2.context.rcTree.onNodeSelect;

    e.preventDefault();
    onNodeSelect(e, _this2);
  };

  this.onCheck = function (e) {
    if (_this2.isDisabled()) return;

    var _props3 = _this2.props,
        disableCheckbox = _props3.disableCheckbox,
        checked = _props3.checked,
        eventKey = _props3.eventKey;
    var _context2 = _this2.context,
        _context2$rcTree = _context2.rcTree,
        checkable = _context2$rcTree.checkable,
        onBatchNodeCheck = _context2$rcTree.onBatchNodeCheck,
        onCheckConductFinished = _context2$rcTree.onCheckConductFinished,
        _context2$rcTreeNode = _context2.rcTreeNode;
    _context2$rcTreeNode = _context2$rcTreeNode === undefined ? {} : _context2$rcTreeNode;
    var onUpCheckConduct = _context2$rcTreeNode.onUpCheckConduct;

    if (!checkable || disableCheckbox) return;

    e.preventDefault();
    var targetChecked = !checked;
    onBatchNodeCheck(eventKey, targetChecked, false, _this2);

    // Children conduct
    _this2.onDownCheckConduct(targetChecked);

    // Parent conduct
    if (onUpCheckConduct) {
      onUpCheckConduct(_this2, targetChecked, false, e);
    } else {
      onCheckConductFinished(e);
    }
  };

  this.onMouseEnter = function (e) {
    var onNodeMouseEnter = _this2.context.rcTree.onNodeMouseEnter;

    onNodeMouseEnter(e, _this2);
  };

  this.onMouseLeave = function (e) {
    var onNodeMouseLeave = _this2.context.rcTree.onNodeMouseLeave;

    onNodeMouseLeave(e, _this2);
  };

  this.onContextMenu = function (e) {
    var onNodeContextMenu = _this2.context.rcTree.onNodeContextMenu;

    onNodeContextMenu(e, _this2);
  };

  this.onDragStart = function (e) {
    var onNodeDragStart = _this2.context.rcTree.onNodeDragStart;

    e.stopPropagation();
    _this2.setState({
      dragNodeHighlight: true
    });
    onNodeDragStart(e, _this2);

    try {
      // ie throw error
      // firefox-need-it
      e.dataTransfer.setData('text/plain', '');
    } catch (error) {
      // empty
    }
  };

  this.onDragEnter = function (e) {
    var onNodeDragEnter = _this2.context.rcTree.onNodeDragEnter;

    e.preventDefault();
    e.stopPropagation();
    onNodeDragEnter(e, _this2);
  };

  this.onDragOver = function (e) {
    var onNodeDragOver = _this2.context.rcTree.onNodeDragOver;

    e.preventDefault();
    e.stopPropagation();
    onNodeDragOver(e, _this2);
  };

  this.onDragLeave = function (e) {
    var onNodeDragLeave = _this2.context.rcTree.onNodeDragLeave;

    e.stopPropagation();
    onNodeDragLeave(e, _this2);
  };

  this.onDragEnd = function (e) {
    var onNodeDragEnd = _this2.context.rcTree.onNodeDragEnd;

    e.stopPropagation();
    _this2.setState({
      dragNodeHighlight: false
    });
    onNodeDragEnd(e, _this2);
  };

  this.onDrop = function (e) {
    var onNodeDrop = _this2.context.rcTree.onNodeDrop;

    e.preventDefault();
    e.stopPropagation();
    _this2.setState({
      dragNodeHighlight: false
    });
    onNodeDrop(e, _this2);
  };

  this.onExpand = function (e) {
    var onNodeExpand = _this2.context.rcTree.onNodeExpand;

    onNodeExpand(e, _this2);
  };

  this.setSelectHandle = function (node) {
    _this2.selectHandle = node;
  };

  this.getNodeChildren = function () {
    var children = _this2.props.children;

    var originList = (0, _toArray2['default'])(children).filter(function (node) {
      return node;
    });
    var targetList = (0, _util.getNodeChildren)(originList);

    if (originList.length !== targetList.length && !onlyTreeNodeWarned) {
      onlyTreeNodeWarned = true;
      (0, _warning2['default'])(false, 'Tree only accept TreeNode as children.');
    }

    return targetList;
  };

  this.getNodeState = function () {
    var expanded = _this2.props.expanded;

    if (_this2.isLeaf()) {
      return null;
    }

    return expanded ? ICON_OPEN : ICON_CLOSE;
  };

  this.isLeaf = function () {
    var _props4 = _this2.props,
        isLeaf = _props4.isLeaf,
        loaded = _props4.loaded;
    var loadData = _this2.context.rcTree.loadData;

    var hasChildren = _this2.getNodeChildren().length !== 0;

    if (isLeaf === false) {
      return false;
    }

    return isLeaf || !loadData && !hasChildren || loadData && loaded && !hasChildren;
  };

  this.isDisabled = function () {
    var disabled = _this2.props.disabled;
    var treeDisabled = _this2.context.rcTree.disabled;

    // Follow the logic of Selectable

    if (disabled === false) {
      return false;
    }

    return !!(treeDisabled || disabled);
  };

  this.syncLoadData = function (props) {
    var expanded = props.expanded;
    var onNodeLoad = _this2.context.rcTree.onNodeLoad;

    // read from state to avoid loadData at same time

    if (expanded && !_this2.isLeaf()) {
      // We needn't reload data when has children in sync logic
      // It's only needed in node expanded
      var hasChildren = _this2.getNodeChildren().length !== 0;
      if (!hasChildren) {
        onNodeLoad(_this2);
      }
    }
  };

  this.renderSwitcher = function () {
    var expanded = _this2.props.expanded;
    var prefixCls = _this2.context.rcTree.prefixCls;

    if (_this2.isLeaf()) {
      return _react2['default'].createElement('span', { className: prefixCls + '-switcher ' + prefixCls + '-switcher-noop' });
    }

    return _react2['default'].createElement('span', {
      className: (0, _classnames2['default'])(prefixCls + '-switcher', prefixCls + '-switcher_' + (expanded ? ICON_OPEN : ICON_CLOSE)),
      onClick: _this2.onExpand
    });
  };

  this.renderCheckbox = function () {
    var _props5 = _this2.props,
        checked = _props5.checked,
        halfChecked = _props5.halfChecked,
        disableCheckbox = _props5.disableCheckbox;
    var _context$rcTree4 = _this2.context.rcTree,
        prefixCls = _context$rcTree4.prefixCls,
        checkable = _context$rcTree4.checkable;

    var disabled = _this2.isDisabled();

    if (!checkable) return null;

    // [Legacy] Custom element should be separate with `checkable` in future
    var $custom = typeof checkable !== 'boolean' ? checkable : null;

    return _react2['default'].createElement('span', {
      className: (0, _classnames2['default'])(prefixCls + '-checkbox', checked && prefixCls + '-checkbox-checked', !checked && halfChecked && prefixCls + '-checkbox-indeterminate', (disabled || disableCheckbox) && prefixCls + '-checkbox-disabled'),
      onClick: _this2.onCheck
    }, $custom);
  };

  this.renderIcon = function () {
    var loading = _this2.props.loading;
    var prefixCls = _this2.context.rcTree.prefixCls;

    return _react2['default'].createElement('span', {
      className: (0, _classnames2['default'])(prefixCls + '-iconEle', prefixCls + '-icon__' + (_this2.getNodeState() || 'docu'), loading && prefixCls + '-icon_loading')
    });
  };

  this.renderSelector = function () {
    var dragNodeHighlight = _this2.state.dragNodeHighlight;
    var _props6 = _this2.props,
        title = _props6.title,
        selected = _props6.selected,
        icon = _props6.icon,
        loading = _props6.loading;
    var _context$rcTree5 = _this2.context.rcTree,
        prefixCls = _context$rcTree5.prefixCls,
        showIcon = _context$rcTree5.showIcon,
        treeIcon = _context$rcTree5.icon,
        draggable = _context$rcTree5.draggable,
        loadData = _context$rcTree5.loadData;

    var disabled = _this2.isDisabled();

    var wrapClass = prefixCls + '-node-content-wrapper';

    // Icon - Still show loading icon when loading without showIcon
    var $icon = void 0;

    if (showIcon) {
      var currentIcon = icon || treeIcon;

      $icon = currentIcon ? _react2['default'].createElement('span', {
        className: (0, _classnames2['default'])(prefixCls + '-iconEle', prefixCls + '-icon__customize')
      }, typeof currentIcon === 'function' ? _react2['default'].createElement(currentIcon, (0, _extends3['default'])({}, _this2.props)) : currentIcon) : _this2.renderIcon();
    } else if (loadData && loading) {
      $icon = _this2.renderIcon();
    }

    // Title
    var $title = _react2['default'].createElement('span', { className: prefixCls + '-title' }, title);

    return _react2['default'].createElement('span', {
      ref: _this2.setSelectHandle,
      title: typeof title === 'string' ? title : '',
      className: (0, _classnames2['default'])('' + wrapClass, wrapClass + '-' + (_this2.getNodeState() || 'normal'), !disabled && (selected || dragNodeHighlight) && prefixCls + '-node-selected', !disabled && draggable && 'draggable'),
      draggable: !disabled && draggable || undefined,
      'aria-grabbed': !disabled && draggable || undefined,

      onMouseEnter: _this2.onMouseEnter,
      onMouseLeave: _this2.onMouseLeave,
      onContextMenu: _this2.onContextMenu,
      onClick: _this2.onSelectorClick,
      onDoubleClick: _this2.onSelectorDoubleClick,
      onDragStart: _this2.onDragStart
    }, $icon, $title);
  };

  this.renderChildren = function () {
    var _props7 = _this2.props,
        expanded = _props7.expanded,
        pos = _props7.pos;
    var _context$rcTree6 = _this2.context.rcTree,
        prefixCls = _context$rcTree6.prefixCls,
        openTransitionName = _context$rcTree6.openTransitionName,
        openAnimation = _context$rcTree6.openAnimation,
        renderTreeNode = _context$rcTree6.renderTreeNode;

    // [Legacy] Animation control

    var renderFirst = _this2.renderFirst;
    _this2.renderFirst = 1;
    var transitionAppear = true;
    if (!renderFirst && expanded) {
      transitionAppear = false;
    }

    var animProps = {};
    if (openTransitionName) {
      animProps.transitionName = openTransitionName;
    } else if ((typeof openAnimation === 'undefined' ? 'undefined' : (0, _typeof3['default'])(openAnimation)) === 'object') {
      animProps.animation = (0, _extends3['default'])({}, openAnimation);
      if (!transitionAppear) {
        delete animProps.animation.appear;
      }
    }

    // Children TreeNode
    var nodeList = _this2.getNodeChildren();

    if (nodeList.length === 0) {
      return null;
    }

    var $children = void 0;
    if (expanded) {
      $children = _react2['default'].createElement('ul', {
        className: (0, _classnames2['default'])(prefixCls + '-child-tree', expanded && prefixCls + '-child-tree-open'),
        'data-expanded': expanded
      }, (0, _util.mapChildren)(nodeList, function (node, index) {
        return renderTreeNode(node, index, pos);
      }));
    }

    return _react2['default'].createElement(_animate2['default'], (0, _extends3['default'])({}, animProps, {
      showProp: 'data-expanded',
      transitionAppear: transitionAppear,
      component: ''
    }), $children);
  };
};

TreeNode.isTreeNode = 1;

exports['default'] = TreeNode;